package com.dzu.gulimall.order.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @author by ZhaoDong
 * @Classname RabbitConfig
 * @Description rabbitmq 配置类
 * @Date 2021/12/19 20:18
 */
@Configuration
public class RabbitConfig {


    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 配置消息转换器，容器中有就用容器里的
     * 默认使用 SimpleMessageConverter
     *
     * @return
     */
    @Bean
    public MessageConverter messageConverter() {
        // 可以序列化为json
        return new Jackson2JsonMessageConverter();
    }


    /**
     * 自定义RabbitTemplate
     * 1、生产者——>broker 回调 ConfirmCallback （只要发布消息，就会回调）
     * 2、exchange——>queue  失败回调 ReturnCallback
     *      设置template.mandatory: true (具体区别 TODO
     * 3、消费端确认（保证每个消息被真正消费，此时才能在queue中删除消息
     *      1、默认是自动确认的（autoACK）只要消息推给消费端，broke就将队列中的消息删除
     *          问题：消费端宕机或者网络抖动会造成  消息丢失
     *          解决： 手动ack，只要没有明确告诉mq消息确认，消息就是unacked。服务器宕机，消息重新归为ready
     */
    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 只要消息抵达broker ack就是true。无论成功与失败，confirm方法都会执行
             * @param correlationData 当前消息的唯一关联（消息的唯一id
             * @param ack 是否成功
             * @param cause 失败原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.print("CorrelationData::=>" + correlationData);
                System.out.print("ack::=>" + ack);
                System.out.print("cause::=>" + cause);
                System.out.println();
            }
        });

        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange,
                                        String routingKey) {
                System.out.println("交换机发送到队列失败才会走此方法。" + message + ":: routingKey" + routingKey);
            }
        });
    }
}
